package ch.wsl.postgres2mapperdao.model

/**
 * 
 * Postgres2mapperdao
 * 
 * @author Andrea Minetti
 *
 * 21 Sep 2012
 * 
 */

import com.googlecode.mapperdao.utils._
import com.googlecode.mapperdao._
import ch.wsl.postgres2mapperdao.common._



class Table (
	val table_name: String,
	val table_type: String,
	val table_schema: String,
	val fields: Set[Column]
) {
  
	lazy val primaryKeys: Option[List[ConstraintColumnUsage]] = {
	  val t = new TableConstraintsDao(DatabaseConnection.mapperDao,DatabaseConnection.queryDao)
	  try {
	    Some(t.primaryKeys(table_schema,table_name).first.refColumns.toList.sortWith((c1, c2) => (c1.column_name compareTo c2.column_name) < 0  ))
	  } catch {
	  	case e: NoSuchElementException => None
	  }
	}
	
	lazy val foreignKeys = {
	  val r = new ReferentialConstraintsDao(DatabaseConnection.mapperDao,DatabaseConnection.queryDao)
	  r.foreignKeys(table_schema,table_name)
	}
	
	def hasKey(key: String):Boolean = {
		if(primaryKeys.isDefined) {
		  primaryKeys.get.find( c => c.column_name == key).isDefined
		} else {
		  false
		}
	}
	
	def isForeignKey(field: String): Boolean = {
		foreignKeys.find(r => r.refColumns.find(c => c.column_name == field).isDefined ).isDefined
	}
	
	
	lazy val table_class: String = {
    
	    val cc = table_name.split("_").map( t =>  t.capitalize ).mkString
	    if(table_name.endsWith("_"))
	      cc+"_"
	    else
	      cc
	 }
	
	lazy val pure_fields: List[Column] = {
	  fields.filter(c => !isForeignKey(c.column_name) || hasKey(c.column_name)).toList.sortWith((c1, c2) => (c1.column_name compareTo c2.column_name) < 0  )
	}
  
}

class TableDao(val mapperDao: MapperDao, val queryDao: QueryDao) extends SimpleCRUD[Table, String] with SimpleAll[Table] {
	import queryDao._
	import Query._
	
	
	def all(schema: String) = query(select from entity where entity.table_schema === schema and entity.table_type === "BASE TABLE")
	
	val entity = TableEntity
}

object TableEntity extends SimpleEntity[Table]("information_schema.tables", classOf[Table]) {
	
	DatabaseConnection.register(this)
  
	val table_name = key("table_name") to (_.table_name)
	val table_type = column("table_type") to (_.table_type)
	val table_schema = column("table_schema") to (_.table_schema)
	val fields = onetomany(ColumnEntity) foreignkey("table_name") to (_.fields)
	
	def constructor(implicit m:ValuesMap) = new Table(table_name,table_type, table_schema, fields) with Persisted

}

class Column (
		val column_name: String,
		val table_name: String,
		val data_type: String,
		val is_nullable: String
) {
  
  def nullable = { is_nullable == "YES" }
  
  def field_type = TypeMapping.postgres2scala.get(data_type).get
  
}

object ColumnEntity extends SimpleEntity[Column]("information_schema.columns", classOf[Column]) {
	
	DatabaseConnection.register(this)
  
	val column_name = key("column_name") to (_.column_name)
	val table_name = key("table_name") to (_.table_name)
	val data_type = column("data_type") to (_.data_type)
	val is_nullable = column("is_nullable") to (_.is_nullable)

	
	def constructor(implicit m:ValuesMap) = new Column(column_name, table_name, data_type,is_nullable) with Persisted

}
